// TARGET_BACKEND: JVM
// WITH_REFLECT
// FULL_JDK

import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
import kotlin.reflect.KClass
import kotlin.reflect.jvm.javaType
import kotlin.test.assertEquals
import kotlin.test.assertTrue

interface A<T>
class Bar

class ArrayOfInvBar : A<Array<Bar>>
class ArrayOfInBar : A<Array<in Bar>>
class ArrayOfOutBar : A<Array<out Bar>>

class ArrayOfInvList : A<Array<List<String>>>
class ArrayOfInList : A<Array<in List<String>>>
class ArrayOfOutList : A<Array<out List<String>>>

fun KClass<*>.getArrayElementType(): Type =
    supertypes.single { it.classifier == A::class }.arguments.single().type!!.arguments.single().type!!.javaType

fun box(): String {
    // NB: in "Array<in X>", Java type of X is always Any::class.java because this is the JVM signature generated by the compiler

    assertEquals(Bar::class.java, ArrayOfInvBar::class.getArrayElementType())
    assertEquals(Any::class.java, ArrayOfInBar::class.getArrayElementType())
    assertEquals(Bar::class.java, ArrayOfOutBar::class.getArrayElementType())

    val invList = ArrayOfInvList::class.getArrayElementType()
    assertTrue(invList is ParameterizedType && invList.rawType == List::class.java, invList.toString())

    assertEquals(Any::class.java, ArrayOfInList::class.getArrayElementType())

    val outList = ArrayOfOutList::class.getArrayElementType()
    assertTrue(outList is ParameterizedType && outList.rawType == List::class.java, outList.toString())

    return "OK"
}
